﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using Fuse8.DomainFramework.Common.Locator;
using Fuse8.DomainFramework.Domain;
using Fuse8.DomainFramework.Common;

namespace Fuse8.DomainFramework.DataAccess.SqlDatabase
{
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TKey"></typeparam>
    public class BaseSqlEntityDataMapper<TEntity, TKey> : ISqlEntityDataMapper<TEntity, TKey>
        where TEntity : class, IEntityObject<TKey>, new()
        where TKey : IComparable<TKey>, IEquatable<TKey>
    {
        private SqlMap<TEntity> _sqlMap = new SqlMap<TEntity>();

        /// <summary>
        /// 
        /// </summary>
        protected SqlMap<TEntity> SqlMap
        {
            get
            {
                return _sqlMap;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public BaseSqlEntityDataMapper()
        { }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ignoreToProperties"></param>
        public BaseSqlEntityDataMapper(IList<string> ignoreToProperties) :
            this(ignoreToProperties, null)
        { }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ignoreToProperties"></param>
        /// <param name="ignoreFromProperties"></param>
        public BaseSqlEntityDataMapper(IList<string> ignoreToProperties, IList<string> ignoreFromProperties)
        {
            if (ignoreToProperties != null)
            {
                foreach (var item in ignoreToProperties)
                {
                    _sqlMap = _sqlMap.WithIgnoreTo(item);
                }
            }

            if (ignoreFromProperties != null)
            {
                foreach (var item in ignoreFromProperties)
                {
                    _sqlMap = _sqlMap.WithIgnoreFrom(item);
                }
            }
        }

        #region ISqlEntityDataMapper<TEntity,TKey> Members

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sp"></param>
        /// <param name="reader"></param>
        /// <returns></returns>
        public virtual TEntity MapFrom(string sp, SqlDataReader reader)
        {
            Guard.ArgumentNotEmpty(sp, "sp");
            Guard.ArgumentNotNull(reader, "reader");

            return _sqlMap.GetEntity(sp, reader);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sp"></param>
        /// <param name="reader"></param>
        /// <param name="stepEntity"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        public virtual TEntity MapFromMulti(string sp, SqlDataReader reader, TEntity stepEntity, int index)
        {
            return null;
        }

    	/// <summary>
    	/// 
    	/// </summary>
    	/// <param name="sp"></param>
    	/// <param name="parameter"></param>
    	/// <param name="isForCreate"></param>
    	/// <returns></returns>
    	public virtual IList<SqlParameter> MapTo(string sp, object parameter, bool isForCreate)
        {
            Guard.ArgumentNotEmpty(sp, "sp");
            var unitOfWork = ((SqlUnitOfWork<TEntity>) UnitOfWorkController<TEntity>.GetCurrentUnitOfWork(false));
    	    IList<SqlProcedureParameter> parameters = null;
    	    if (unitOfWork != null)
            {
                parameters = SchemaBuilder.Current.GetStoredProcedureParameters(unitOfWork.Connection,
                                                                                    unitOfWork.Transaction, sp);
                if (isForCreate && !parameters.Any(p => p.Name.Equals("Id", StringComparison.OrdinalIgnoreCase)))
                {
                    parameters.Add(new SqlProcedureParameter("Id"));
                }
            }
    	    return _sqlMap.GetParamInfo(sp, parameter, isForCreate, parameters);
        }

        public virtual void MapFrom(string sp, TEntity entity, Dictionary<string, object> values)
        {
            _sqlMap.UpdateEntity(sp, entity, values);
        }

        #endregion
    }
}
